//
// Created by 郝羽 on 2017/12/12.
//

#ifndef RTC_XSWITCH2_OVERUSE_DETECTOR_HPP
#define RTC_XSWITCH2_OVERUSE_DETECTOR_HPP

#include "bwe/bwe.hpp"

namespace bwe {

class OveruseDetector {
public:
    void DetectUsage(int64_t now_ms, double ts_delta, double normalized_offset, int deltas) {
        if (deltas < 2) {
            return;
        }

        //std::cout << "offset: " << normalized_offset << " threshold: " << offset_threshold_ << " time-overusing: " << time_over_using_ << " count-overusing: " << count_over_using_ << std::endl;
        if (normalized_offset > offset_threshold_) {
            if (time_over_using_ == -1) {
                time_over_using_ = ts_delta / 2;
            } else {
                time_over_using_ += ts_delta;
            }
            count_over_using_ += 1;
            if (time_over_using_ > time_over_using_threshold_ && count_over_using_ > 1) {
                if (normalized_offset >= prev_offset_) {
                    time_over_using_ = 0;
                    count_over_using_ = 0;
                    usage_ = Usage::OverUsing;
                }
            }
//        } else if (normalized_offset < -offset_threshold_) {
        } else if (normalized_offset < -offset_threshold_ * 1.2) {
            time_over_using_ = -1;
            count_over_using_ = 0;
            usage_ = Usage::UnderUsing;
        } else {
            time_over_using_ = -1;
            count_over_using_ = 0;
            usage_ = Usage::Normal;
        }
        prev_offset_ = normalized_offset;
        updateThreshold(now_ms, normalized_offset);
    };

    Usage Hypothesis() {
        return usage_;
    };

    double Threshold() {
        return offset_threshold_;
    };

private:
    void updateThreshold(int64_t now_ms, double normalized_offset) {
        if (offset_threshold_update_ms_ == -1) {
            offset_threshold_update_ms_ = now_ms;
        }
        if (std::fabs(normalized_offset) > offset_threshold_ + offset_adapt_ms_) {
            offset_threshold_update_ms_ = now_ms;
            return;
        }
        const double k = std::fabs(normalized_offset) < offset_threshold_ ? offset_k_down_ : offset_k_up_;
        int64_t update_interval_ms = std::min(now_ms - offset_threshold_update_ms_, update_interval_max_);
        offset_threshold_ += k * (std::fabs(normalized_offset) - offset_threshold_) * update_interval_ms;
        offset_threshold_ = std::min(offset_threshold_, offset_threshold_max_);
        offset_threshold_ = std::max(offset_threshold_, offset_threshold_min_);
        offset_threshold_update_ms_ = now_ms;
    };

private:
    const double time_over_using_threshold_ = 10.0;
//    const double time_over_using_threshold_ = 100.0;
    const int64_t update_interval_max_ = 100;
    const double offset_k_up_ = 0.0087;
    const double offset_k_down_ = 0.039;
    const double offset_threshold_max_ = 600;
    const double offset_threshold_min_ = 6;

    Usage           usage_              = Usage::Normal;
    double          offset_threshold_   = 12.5;
    double          time_over_using_    = -1;
    int             count_over_using_   = 0;
    int64_t offset_threshold_update_ms_ = -1;
    double          offset_adapt_ms_    = 15.0;
    double          prev_offset_        = 0.0;
};

}
#endif //RTC_XSWITCH2_OVERUSE_DETECTOR_HPP
